package com.atguigu.gmall.mq;


import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitOperations;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.amqp.RabbitTemplateConfigurer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * RabbitMQ的配置
 * 1、RabbitMQ的自动配置 RabbitAutoConfiguration
 * 1)、RabbitProperties 封装所有可以配置属性
 * 2)、RabbitTemplateConfigurer；自定义修改 RabbitTemplate
 * 3）、RabbitTemplate：  RedisTemplate，ElasticSearchTemplate; 操作rabbitmq的客户端
 * 4)、AmqpAdmin： 管理RabbitMQ，增删改查queue，exchange等
 *
 */
@EnableRabbit //开启rabbit功能
@Configuration
public class AppRabbitConfig {


    //把要给rabbitmq中放的队列、交换机、绑定关系，@Bean放在容器中，也会自动创建

    /**
     * 订单的交换机
     * @return
     */
   @Bean
   public Exchange orderEventExchange(){
       /**
        * String name,  交换机名字
        * boolean durable,  持久化
        * boolean autoDelete, 是否自动删除
        * Map<String, Object> arguments, 交换机的参数设置
        */
       return new TopicExchange(RabbitConst.ORDER_EXCHANGE,true,false);
   }


    /**
     * 延时队列
     * @return
     */
   @Bean
   public Queue orderDelayQueue(){
       /**
        * String name,  队列的名字
        * boolean durable, 持久化
        * boolean exclusive, 排他的
        * boolean autoDelete, 自动删除
        * @Nullable Map<String, Object> arguments
        * 延迟队列的设置项
        * x-dead-letter-exchange: order-event-exchange 信死了，也不要丢，丢给谁
        * x-dead-letter-routing-key: order.release.order 用哪个路由键
        * x-message-ttl: 60000 消息过期时间
        */
       Map<String, Object> arguments = new HashMap<>();
       arguments.put("x-dead-letter-exchange",RabbitConst.ORDER_EXCHANGE);
       arguments.put("x-dead-letter-routing-key","order.release.order");
       arguments.put("x-message-ttl",60000*30); //1min过期
       return new Queue(RabbitConst.ORDER_DELAY_QUEUE,true,false,false,arguments);
   }

   @Bean
   public Queue orderReleaseOrderQueue(){
       return new Queue(RabbitConst.ORDER_RELEASE_QUEUE,true,false,false);
   }


    /**
     * 交换机和延时队列绑定
     * @return
     */
   @Bean
   public Binding orderCreateOrderBinding(){
       /**
        * String destination, 目的地
        * DestinationType destinationType, 目的地类型
        * String exchange, 交换机
        * String routingKey, 路由键
        * @Nullable Map<String, Object> arguments 参数设置项
        */
      return new Binding(RabbitConst.ORDER_DELAY_QUEUE,
              Binding.DestinationType.QUEUE,
              RabbitConst.ORDER_EXCHANGE,
              RabbitConst.CREATE_ORDER_RK,null);
   }

    /**
     * 交换机和死信队列的绑定
     * @return
     */
   @Bean
   public Binding releaseOrderBinding(){
       return new Binding(RabbitConst.ORDER_RELEASE_QUEUE,
               Binding.DestinationType.QUEUE,
               RabbitConst.ORDER_EXCHANGE,
               "order.release.order",null);
   }






    /**
     * 1、服务端确认模式 + 消费端手动确认模式配置
     */

    @Bean
    public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate();
        configurer.configure(template, connectionFactory);
        // CorrelationData correlationData, 消息的联合数据，消息的主键
        // boolean ack 服务返回true代表消息服务器已经收到,
        // @Nullable String cause
        template.setConfirmCallback((correlationData,ack,cause)->{
            if(ack){
                System.out.println("服务器收到了消息....");
            }else {
                System.out.println("服务器没有收到消息...."+correlationData.getReturnedMessage());
                //TODO 存数据库重试，再发送重试
            }
        });

        //
        //Message message, int replyCode, String replyText, String exchange, String routingKey
        template.setReturnCallback((message,replyCode,replyText,exchange,routingKey)->{
            //消息服务器没有处理成功 消息投递队列
            System.out.println(message+": 投递到队列失败。");
            System.out.println("响应状态码："+replyCode);
            System.out.println("响应文本："+replyText);
            System.out.println("服务器收到的消息："+message);
            System.out.println("消息交换机："+exchange);
            System.out.println("消息路由件键："+routingKey);

        });
        return template;
    }


}
